﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using SLRT.business.api;
using Emgu.CV;
using Emgu.CV.Structure;
using System.ComponentModel;
using SLRT.usercontrols;
using Emgu.CV.UI;
using System.Windows.Forms;
using SLRT.business.src;

namespace TestApplication.business.src
{
    class MovementBrain : IMovementBrain
    {
        private static readonly ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim();
        private Bitmap image;
        private bool runThread;
        private bool changed;
        private double[,] buttons;
        public event PropertyChangedEventHandler BarEvent;
        private double wRatio;
        private double hRatio;
        private bool[] buttonPressedForButtonBar;
        private int[] currentSteadyFramesForButtonBar;
        private bool[] buttonPressedForSideBar;
        private int[] currentSteadyFramesForSideBar;
        private const int STEADY_FRAMES_THRESHOLD = 3;
        private bool newImageFromWebcam;

        private Image<Bgr, Byte> webcamImage;
        private Image<Bgr, Byte> cutImageForButtons;
        private Image<Bgr, Byte> cutImageForSideBar;
        private Image<Gray, Byte> rangeImageForButtons;
        private Image<Gray, Byte> rangeImageForSideBar;
        private Rectangle interestRectangleForButtons;
        private Rectangle interestRectangleForSideBar;
        private Rectangle[] rectanglesForButtons;
        private Rectangle[] rectanglesForSideBar;
        private int buttonAreaForButtonBar;
        private int buttonAreaForSideBar;
        private const int BAR_TIMER = 6;
        private const int BUTTON_TIMER = 3;
        private int elapsedBarTime;
        private int elapsedButtonTime;
        private bool[] activeButtons;
        private bool sideBarButtonsEnabled;

        private static readonly Object lockObject01 = new Object();

        #region Properties
        public Bitmap Image
        {
            get
            {
                rwlock.EnterWriteLock();
                try
                {
                    return image;
                }
                finally
                {
                    rwlock.ExitWriteLock();
                }
            }
            set
            {
                rwlock.EnterWriteLock();
                try
                {
                    image = value;
                }
                finally
                {
                    rwlock.ExitWriteLock();
                }
            }
        }
        public bool RunThread
        {
            get { return runThread; }
            set { runThread = value; }
        }

        
        public bool NewImageFromWebcam
        {
            get { return newImageFromWebcam; }
            set {
                lock (lockObject01)
                {
                    newImageFromWebcam = value;
                }
            }
        }


        public bool Changed
        {
            get { return changed; }
            set { changed = value; }
        }
        #endregion

        public MovementBrain(ButtonBarControl buttonBar, System.Windows.Controls.Image displayImage)
        {
            int imageWidth = CaptureModel.Instance.Image.Width;
            int imageHeight = CaptureModel.Instance.Image.Height;

            this.buttons = buttonBar.getButtonPositions();
            this.wRatio = displayImage.ActualWidth / imageWidth;
            this.hRatio = displayImage.ActualHeight / imageHeight;

            interestRectangleForButtons = new Rectangle(0, 0, imageWidth, Convert.ToInt32(100 / this.wRatio));
            rectanglesForButtons=new Rectangle[buttons.GetLength(0)];
            buttonPressedForButtonBar = new bool[buttons.GetLength(0)];
            currentSteadyFramesForButtonBar = new int[buttons.GetLength(0)];

            for(int i=0;i<buttons.GetLength(0);i++)
            {
                rectanglesForButtons[i]=new Rectangle(Convert.ToInt32(buttons[i,0]/this.wRatio),Convert.ToInt32(buttons[i,1]/this.wRatio),Convert.ToInt32((buttons[i,2]-buttons[i,0])/this.wRatio),Convert.ToInt32((buttons[i,3]-buttons[i,1])/this.wRatio));
            }

            buttonAreaForButtonBar = getArea(rectanglesForButtons[0]);

            OnBarEvent(new PropertyChangedEventArgs("SIDEBAR,disable"));

        }

        public void OnBarEvent(PropertyChangedEventArgs e)
        {
            if (BarEvent != null)
                BarEvent(this, e);
        }


        private Image<Gray, Byte> detectSkin(Image<Bgr, Byte> Img)
        {
            Image<Ycc, Byte> currentYCrCbFrame = Img.Convert<Ycc, Byte>();
            Image<Gray, byte> skin = new Image<Gray, byte>(Img.Width, Img.Height);
            skin = currentYCrCbFrame.InRange(new Ycc(0, 131, 80), new Ycc(255, 185, 135));
            StructuringElementEx rect_12 = new StructuringElementEx(12, 12, 6, 6, Emgu.CV.CvEnum.CV_ELEMENT_SHAPE.CV_SHAPE_RECT);
            CvInvoke.cvErode(skin, skin, rect_12, 1);
            StructuringElementEx rect_6 = new StructuringElementEx(6, 6, 3, 3, Emgu.CV.CvEnum.CV_ELEMENT_SHAPE.CV_SHAPE_RECT);
            CvInvoke.cvDilate(skin, skin, rect_6, 2);
            return skin;
        }

        private int getArea(Rectangle r)
        {
            return r.Width * r.Height;
        }


        public void Run()
        {

            Rectangle biggestBlobForButtons;
            //ImageViewer viewer1 = new ImageViewer();
            //Thread aThread = new Thread(delegate() { viewer1.ShowDialog(); });
            //aThread.Start();
            ImageViewer viewer2 = new ImageViewer();
            Thread otherThread = new Thread(delegate() { viewer2.ShowDialog(); });
            otherThread.Start();

            while (runThread)
            {
                if (this.newImageFromWebcam)
                {
                    //this.newImageFromWebcam = false;
                    this.Image = new Bitmap(CaptureModel.Instance.Image);
                    webcamImage = new Image<Bgr, byte>(this.Image);

                    NewImageFromWebcam = false;

                    this.Image.Dispose();
                    cutImageForButtons = webcamImage.Copy(interestRectangleForButtons);
                    rangeImageForButtons = detectSkin(cutImageForButtons);
                    cutImageForButtons.Dispose();
                    //viewer1.Image = rangeImageForSideBar;
                    viewer2.Image = rangeImageForButtons;

                    using (MemStorage storage = new MemStorage())
                    {
                        Contour<Point> contour = rangeImageForButtons.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST, storage);
                        Contour<Point> biggest = null;

                        double currentArea = 0, maxArea = 0;

                        while (contour != null)
                        {
                            currentArea = contour.Area;
                            if (currentArea > maxArea)
                            {
                                maxArea = currentArea;
                                biggest = contour;
                            }
                            contour = contour.HNext;
                        }
                        if (biggest != null)
                            biggestBlobForButtons = biggest.BoundingRectangle;
                        else
                            biggestBlobForButtons = Rectangle.Empty;
                    }
                    if (biggestBlobForButtons.IsEmpty)
                    {
                        continue;
                    }
                    
                    for (int i = 0; i < rectanglesForButtons.Length; i++)
                    {
                        Rectangle intersection = rectanglesForButtons[i];
                        intersection.Intersect(biggestBlobForButtons);
                        if (!intersection.IsEmpty && getArea(intersection) > 0.5 * getArea(rectanglesForButtons[i]))
                        {
                            if (!buttonPressedForButtonBar[i])
                            {
                                currentSteadyFramesForButtonBar[i]++;
                                if (currentSteadyFramesForButtonBar[i] == STEADY_FRAMES_THRESHOLD)
                                {
                                    currentSteadyFramesForButtonBar[i]=0;
                                    buttonPressedForButtonBar[i] = true;
                                    OnBarEvent(new PropertyChangedEventArgs("BUTTON," + i));
                                    Console.WriteLine("BUTTON," + i);
                                }
                            }
                        }
                        else
                        {
                            buttonPressedForButtonBar[i] = false;
                            currentSteadyFramesForButtonBar[i] = 0;
                        }
                    }
                }
                else
                {
                    resetButtonBar();
                }
                                        
                
                Thread.Sleep(300);
            }
        }
        private void resetButtonBar()
        {
            for (int i = 0; i < rectanglesForButtons.Length; i++)
            {
                currentSteadyFramesForButtonBar[i] = 0;
                buttonPressedForButtonBar[i] = false;
            }
        }
    }
}
